/**
 * 
 */
package org.rollinitiative.d20.combat;

import java.util.EnumMap;
import java.util.EnumSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rollinitiative.d20.AdjustableValue;
import org.rollinitiative.d20.Adjustment;
import org.rollinitiative.d20.dice.Dice;
import org.rollinitiative.d20.entity.Ability;
import org.rollinitiative.d20.entity.AbilityListenerValue;
import org.rollinitiative.d20.entity.AbilityValue;
import org.rollinitiative.d20.entity.Size;

/**
 * @author bebopjmm
 * 
 */
public class Defense
{
    static final Log LOG_ = LogFactory.getLog(Defense.class);

    public enum AC_Type {
        AC_Reg, AC_Touch;
    }

    EnumMap<AC_Type, AbilityListenerValue> armorClass_;

    Adjustment sizeAdj_;

    boolean rollDefense_ = true;

    boolean isFlatFooted_ = true;

    Dice dice_ = Dice.getInstance();


    public Defense(Size size, AbilityValue dexterityAbility)
    {
        sizeAdj_ = Size.generateCombatAdjustment(size);
        armorClass_ = new EnumMap<AC_Type, AbilityListenerValue>(AC_Type.class);

        AbilityListenerValue acEntry = null;
        for (AC_Type ac : EnumSet.range(AC_Type.AC_Reg, AC_Type.AC_Touch)) {
            acEntry = new AbilityListenerValue(0, dexterityAbility);
            acEntry.addAdjustment(sizeAdj_);
            armorClass_.put(ac, acEntry);
        }

    }


    public void setBaseDefenseBonus(int baseDefenseBonus)
    {
        LOG_.info("Setting baseDefenseBonus to: " + baseDefenseBonus);
        AbilityListenerValue acEntry = null;
        for (AC_Type ac : armorClass_.keySet()) {
            acEntry = armorClass_.get(ac);
            acEntry.setBase(baseDefenseBonus);
        }
    }


    /**
     * @param newSize
     */
    public void setSize(Size newSize)
    {
        sizeAdj_.setValue(newSize.getCombatModifier());
    }


    public boolean isFlatFooted()
    {
        return this.isFlatFooted_;
    }


    public void setFlatFooted(boolean isFlatFooted)
    {
        this.isFlatFooted_ = isFlatFooted;
        AbilityListenerValue acEntry = null;
        if (isFlatFooted) {
            LOG_.info("Limiting DEX bonus for AC to 0");
            for (AC_Type ac : EnumSet.range(AC_Type.AC_Reg, AC_Type.AC_Touch)) {
                acEntry = armorClass_.get(ac);
                acEntry.setLimiter(Ability.DEX, 0);
            }
        }
        else {
            LOG_.info("Removing DEX bonus limits for AC");
            for (AC_Type ac : EnumSet.range(AC_Type.AC_Reg, AC_Type.AC_Touch)) {
                acEntry = armorClass_.get(ac);
                acEntry.removeLimiter(Ability.DEX);
            }
        }
    }


    public int defend(boolean touchAttack)
    {
        // NO Dex bonus if flatFooted
        // NO AC bonus if touch
        int defense = 0;
        if (rollDefense_) {
            int baseRoll = dice_.roll(1, 20, 0);
            defense = baseRoll;
        }
        defense += armorClass_.get(AC_Type.AC_Reg).getCurrent();
        return defense;
    }


    public int defend(int playerRoll, boolean touchAttack)
    {
        return playerRoll + armorClass_.get(AC_Type.AC_Reg).getCurrent();
    }


    public AdjustableValue getArmorClass(AC_Type selection)
    {
        return armorClass_.get(selection);
    }

}
